// *** ADDED BY HEADER FIXUP ***
#include <wx/ffile.h>
// *** END ***
// *** ADDED BY HEADER FIXUP ***
#include <wx/wfstream.h>
// *** END ***
// *** ADDED BY HEADER FIXUP ***
#include <wx/datetime.h>
// *** END ***
#include "PhoneAimlManager.h"
#include <fstream>
#include <iostream>
#include <wx/xml/xml.h>
#include <wx/textfile.h>
#include "MyException.h"
#include "Mysocket.h"
using namespace std;

PhoneAiml::PhoneAiml(const wxString& queryType, const wxString& stdQuery)
    :queryType(queryType),stdQuery(stdQuery),needWrite(false)
{
    wxString fp = wxT("PhoneAiml/")+queryType+wxT(".aiml");
    FILE* file = fopen(fp.mb_str(wxConvLocal).data(),"r");
    if(file==NULL) puts("fopen fail!");
    wxFFile ffile(file);
    wxFFileInputStream fs(ffile);
    if(!Load(fs))
    {
        printf("Error!");
        SetRoot(new wxXmlNode(wxXML_ELEMENT_NODE,wxT("aiml")));
        //Save(file,2);
    }
	SetFileEncoding(wxT("UTF-8"));
}

void PhoneAiml::AddCategory(const wxString& query, const wxString& that,
                            const wxString& answer, const wxString& name)
{

    cout<<"------------------AddCategory--------------"<<endl
        <<"StdQuery: "<<stdQuery.mb_str(wxConvLocal).data()<<endl
        <<"Query: "<<query.mb_str(wxConvLocal).data()<<endl
        <<"That: "<<that.mb_str(wxConvLocal).data()<<endl
        <<"Answer: "<<answer.mb_str(wxConvLocal).data()<<endl;

    wxXmlNode* cg = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("category"));
    cg->AddAttribute(wxT("createTime"),wxDateTime::Now().Format());
    cg->AddAttribute(wxT("contributor"),name);

    wxXmlNode* pn = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("pattern"));
    pn->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,query));
    cg->AddChild(pn);

    if(!that.empty())
    {
        pn = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("that"));
        cg->AddChild(pn);
        pn->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,that));
    }

    pn = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("template"));
    cg->AddChild(pn);
    if(answer.empty())
    {
        pn->AddChild(new wxXmlNode(wxXML_ELEMENT_NODE,wxT("srai")));
        pn->GetChildren()->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,stdQuery));
    }
    pn->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,answer));
    //printf("Root: %s child:%d next:%d\n",GetRoot()->GetName().mb_str(wxConvLocal).data(),
    //           GetRoot()->GetChildren(),cg->GetNext());
   // wxXmlDocument tmp;
    //tmp.SetRoot(new wxXmlNode(wxXML_ELEMENT_NODE,wxT("aiml")));
    //tmp.GetRoot()->AddChild(cg);
   // tmp.Save(wxT("./PhoneAiml/tmp.aiml"));
    //tmp.GetRoot()->SetChildren(NULL);
    //cg->SetParent(NULL);

    GetRoot()->AddChild(cg);
    needWrite = true;
}
bool PhoneAiml::Save()
{
    //if(!needWrite) return true; /**< 延迟保存~后来因为不明真相的alice原因取消 */
    wxString file = wxT("PhoneAiml/")+queryType+wxT(".aiml");
    needWrite = false;
    return wxXmlDocument::Save(file,2);
}
wxString& PhoneAiml::GetStdQuery()
{
    return stdQuery;
}



PhoneAimlManager::PhoneAimlManager(Kernel *kernel):kernel(kernel)
{
    ReadData(wxT("./PhoneAiml/list.xml"));
}

PhoneAimlManager::~PhoneAimlManager()
{
    SaveData();
}


/** \brief 读取list.xml文件
 *
 * 从中提取各个结点的标准咨询类型和标准问句等信息\n
 * 文件名就是咨询类型名+.aiml
 *
 */

void PhoneAimlManager::ReadData(const wxString& fp)
{
    if(!typeList.Load(fp)) return ;

    wxXmlNode *responedChild = typeList.GetRoot();

    if(responedChild->GetName()!=wxT("List"))
    {
        delete(typeList.DetachRoot());
        return;
    }
    else responedChild = responedChild->GetChildren();
    while(responedChild)
    {
        if(responedChild->GetName() == wxT("Respond"))
        {
            wxString desc,sdq; /**< desc为咨询类型, fp为相应AIML文件地址, sdq为标准问句  */
            wxXmlNode *child = responedChild->GetChildren();
            while(child)
            {
                if(child->GetName() == wxT("QueryType"))
                {
                    desc = child->GetNodeContent();
                }
                if(child->GetName() == wxT("Query"))
                {
                    sdq = child->GetNodeContent();
                }
                child = child->GetNext();
            }
            wxString fn = desc + wxT(".aiml");
            puts("---------------------------------------------------");
            printf("Reading Query Option:\nType describe: %s\nFile name: %s\nStandard query: %s\n",
                   desc.mb_str(wxConvLocal).data(),
                   fn.mb_str(wxConvLocal).data(),
                   sdq.mb_str(wxConvLocal).data());
            puts("---------------------------------------------------");
            mp.insert(make_pair(desc,new PhoneAiml(desc,sdq)));
            timeSort.insert(make_pair(time(0),desc));
            kernel->respond(string("LOAD PhoneAiml/")+desc.mb_str(wxConvLocal).data(),"system");
        }
        responedChild = responedChild->GetNext();
    }
    pre = mp.size();
}

void PhoneAimlManager::SaveData()
{
    mutex.Lock();
    if(pre!=mp.size())
    {
        typeList.SetFileEncoding(wxT("UTF-8"));
        typeList.Save(wxT("./PhoneAiml/list.xml"),2);
        pre = mp.size();
    }
    /*for(map<wxString,PhoneAiml*>::iterator it=mp.begin();
        it!=mp.end();++it)
        {
            it->second->Save();
        }
        */
    mutex.Unlock();
}


string PhoneAimlManager::AddCategory(wxXmlNode *node,const wxString& name)
{
    //获取node结点中的信息
    wxString desc, query, that, answer;
    wxXmlNode *child = node;
    while(child)
    {
        if(child->GetName() == wxT("QueryType"))
        {
            desc = child->GetNodeContent();
        }
        if(child->GetName() == wxT("Query"))
        {
            query = child->GetNodeContent();
        }
        if(child->GetName() == wxT("That"))
        {
            that = child->GetNodeContent();
        }
        if(child->GetName() == wxT("Answer"))
        {
            answer = child->GetNodeContent();
        }
        child = child->GetNext();
    }
    if(desc.empty()) return "";
    //检查node结点中的咨询类型是否已经存在
    //flag==true则已经存在，否则不存在
    bool flag = mp.find(desc)!=mp.end(); /**< 直接查找咨询类型是否存在 */

    if(flag) //如果node结点在List中已经存在
    {
        mp[desc]->AddCategory(query,that,wxT(""),name);
        mp[desc]->Save();
        //kernel->respond("Load PhoneAiml/tmp","system");
    }
    else //如果不存在
    {
        wxXmlNode* root = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("Respond"));

        wxXmlNode* nt = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("QueryType"));
        nt->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,desc));
        root->AddChild(nt);

        nt = new wxXmlNode(wxXML_ELEMENT_NODE,wxT("Query"));
        nt->AddChild(new wxXmlNode(wxXML_TEXT_NODE,wxEmptyString,query));
        root->AddChild(nt);

        typeList.GetRoot()->AddChild(root);

        //再新建aiml文件并加入时间戳
        mp.insert(make_pair(desc,new PhoneAiml(desc,query)));
        timeSort.insert(make_pair(time(0),desc));
        mp[desc]->AddCategory(query,wxT(""),answer,name);
        mp[desc]->Save();
        kernel->respond(string("Load PhoneAiml/")+desc.mb_str(wxConvLocal).data()+".aiml","system");
    }
    wxString ask = mp[desc]->GetStdQuery();
    return kernel->respond(ask.utf8_str().data(),name.utf8_str().data());
}
void PhoneAimlManager::SendQueryType(wxSocketBase* sock,time_t timeStamp)
{
    wxString msg = wxT("<Setting>");
    bool send = false;
    for(map<time_t,wxString>::iterator it=timeSort.begin();
            it!=timeSort.end()&&it->first>timeStamp; ++it)
    {
        send = true;
        msg += wxT("<AddQueryType>")+it->second+wxT("</AddQueryType>\n");
    }
    if(!send) return;
    msg += wxT("</Setting>");
    Mysocket::SendString(sock,msg);
    Mysocket::ReceiveString(sock,msg);
    if(msg!=wxT("<Ack>Setting</Ack>")) throw ServerException(XmlParseFail);
    return;
}
